package cn.lingyangwl.agile.msg.push.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.lingyangwl.agile.common.security.utils.*;
import cn.lingyangwl.agile.model.constants.*;
import cn.lingyangwl.agile.model.enums.*;
import cn.lingyangwl.agile.model.module.auth.*;
import cn.lingyangwl.agile.model.module.tenant.*;
import cn.lingyangwl.agile.msg.push.*;
import cn.lingyangwl.agile.msg.push.api.constatnts.*;
import cn.lingyangwl.agile.msg.push.assembly.*;
import cn.lingyangwl.agile.msg.push.core.*;
import cn.lingyangwl.agile.msg.push.mapper.*;
import cn.lingyangwl.agile.msg.push.model.entity.*;
import cn.lingyangwl.agile.msg.push.model.rqrs.notice.*;
import cn.lingyangwl.agile.msg.push.service.*;
import cn.lingyangwl.agile.tenant.core.*;
import cn.lingyangwl.agile.tenant.core.utils.*;
import cn.lingyangwl.framework.tool.core.*;
import cn.lingyangwl.framework.tool.core.exception.*;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 消息设置
 *
 * @author shenguangyang
 */
@Slf4j
@Service
public class NoticeChannelServiceImpl extends ServiceImpl<NoticeChannelMapper, NoticeChannel>
    implements IService<NoticeChannel>, NoticeChannelService {
    @Resource
    private NoticeChannelAssembly noticeChannelAssembly;
    @Resource
    private NoticeChannelMapper noticeChannelMapper;
    @Resource
    private TenantDataIsolateService dataIsolateService;
    @Resource
    @Lazy
    private MsgNoticeService noticeService;

    @Override
    @Tenant(level = DataIsolateLevel.MGT)
    public List<NoticeChannel> listChannelByNoticeIds(List<Long> noticeIds) {
        if (CollUtil.isEmpty(noticeIds)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<NoticeChannel> lqw = NoticeChannel.lqw().in(NoticeChannel::getNoticeId, noticeIds);
        List<NoticeChannel> list = this.list(lqw);
        dataIsolateService.processQueryResult(list);
        return list;
    }

    @Override
    @Tenant(level = DataIsolateLevel.MGT)
    public NoticeChannel getNoticeChannel(Long id) {
        // 查询也包括被删除的, 需要自定义sql且实体类中不能使用mybatis-plus的类型转换器
        NoticeChannel resp = noticeChannelMapper.getChannelById(id);
        dataIsolateService.processQueryResult(resp);
        return resp;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveNoticeChannel(NoticeChannelSaveReq req) {

        NoticeChannel entity = noticeChannelAssembly.toNoticeChannel(req);
        MsgSettings settings = JSON.parseObject(entity.getSettings(), MsgSettings.class);
        entity.setTemplateId(settings.getTemplateId());
        this.save(entity);
        dataIsolateService.saveData(entity);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateNoticeChannel(NoticeChannelSaveReq req) {
        NoticeChannel entity = noticeChannelAssembly.toNoticeChannel(req);

        NoticeChannel oldChannel = TenantUtils.executeIgnore(() -> this.getById(req.getId()));
        if (Objects.isNull(oldChannel)) {
            throw new BizException("消息渠道不存在");
        }

        TenantContext tenantContext = TenantContext.get();
        MsgSettings settings = JSON.parseObject(entity.getSettings(), MsgSettings.class);
        entity.setTemplateId(settings.getTemplateId());
        if (tenantContext.isMgtSceneTenant()) {
            return this.updateById(entity);
        }
        dataIsolateService.updateData(entity);
        return true;
    }

    @Override
    public void deleteChannelByNoticeIds(List<Long> noticeIds) {
        if (CollectionUtils.isEmpty(noticeIds)) {
            return;
        }
        LambdaQueryWrapper<NoticeChannel> lqw = NoticeChannel.lqw().in(NoticeChannel::getNoticeId, noticeIds);
        List<Long> channelIds = this.list(lqw).stream().map(NoticeChannel::getId).collect(Collectors.toList());

        dataIsolateService.deleteData(TenantDataType.MSG_CHANNEL, channelIds);
        this.remove(lqw);
    }

    @Override
    public void deleteChannelByNoticeId(Long noticeId, List<String> channelTypes) {
        if (Objects.isNull(noticeId) || CollUtil.isEmpty(channelTypes)) {
            return;
        }
        LambdaQueryWrapper<NoticeChannel> lqw = NoticeChannel.lqw()
            .eq(NoticeChannel::getNoticeId, noticeId).in(NoticeChannel::getChannelType, channelTypes);
        List<Long> channelIds = this.list(lqw).stream().map(NoticeChannel::getId).collect(Collectors.toList());

        dataIsolateService.deleteData(TenantDataType.MSG_CHANNEL, channelIds);
        this.remove(lqw);
    }

    @Override
    @Tenant(level = DataIsolateLevel.MGT)
    public List<NoticeChannel> listChannel(Long noticeId, String channelType) {
        LambdaQueryWrapper<NoticeChannel> lqw = NoticeChannel.lqw().eq(NoticeChannel::getNoticeId, noticeId)
            .eq(StringUtils.isNotEmpty(channelType), NoticeChannel::getChannelType, channelType);

        List<NoticeChannel> list = this.list(lqw);
        dataIsolateService.processQueryResult(list);
        return list.stream().filter(e -> CommonCons.UseStats.NORMAL.equals(e.getStatus())).collect(Collectors.toList());
    }

    @Override
    @Tenant(level = DataIsolateLevel.MGT)
    public List<String> listTemplateIdsByCodes(List<String> noticeCodes) {
        if (CollUtil.isEmpty(noticeCodes)) {
            return Collections.emptyList();
        }
        // 判断用户终端(来源)
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String terminal = loginUser.getTerminal();
        String channelType;
        if (TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal().equals(terminal)) {
            channelType = ChannelTypeEnum.WX_MINI_APP.getCode();
        } else if (TerminalEnum.WECHAT_WAP.getTerminal().equals(terminal)) {
            channelType = ChannelTypeEnum.WX_MINI_APP.getCode();
        } else {
            log.warn("用户登录的终端 [{}] 暂时不支持获取模板ids", terminal);
            return Collections.emptyList();
        }

        Set<Long> noticeIds = noticeService.listNoticeByCodes(noticeCodes).stream().map(MsgNotice::getId).collect(Collectors.toSet());
        if (CollUtil.isEmpty(noticeIds)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<NoticeChannel> lqw = NoticeChannel.lqw().eq(NoticeChannel::getChannelType, channelType)
            .in(NoticeChannel::getNoticeId, noticeIds);
        List<NoticeChannel> list = this.list(lqw);
        dataIsolateService.processQueryResult(list);
        return list.stream()
            .filter(e -> StringUtils.isNotEmpty(e.getTemplateId()) && CommonCons.UseStats.NORMAL.equals(e.getStatus()))
            .map(NoticeChannel::getTemplateId).collect(Collectors.toList());
    }
}
